package elka.gis.postman.helper.impl;

import elka.gis.postman.bean.Graph;
import elka.gis.postman.bean.Path;
import elka.gis.postman.common.Constants;
import elka.gis.postman.helper.DijkstraSearcher;
import elka.gis.postman.helper.EulerCycleSearcher;
import elka.gis.postman.helper.GraphConnectivityChecker;
import elka.gis.postman.helper.GraphHelper;

/**
 * Klasa pozwalajca na wyszukanie sciezki listonosza
 * @author Wojtek
 *
 */
public class GraphHelperImpl implements GraphHelper {

	private final GraphConnectivityChecker connectivityChecker;
	private final EulerCycleSearcher eulerCycleSearcher;
	private final DijkstraSearcher dijkstraSearcher;

	public GraphHelperImpl(GraphConnectivityChecker connectivityChecker,
			EulerCycleSearcher eulerCycleSearcher,
			DijkstraSearcher dijkstraSearcher) {
		this.connectivityChecker = connectivityChecker;
		this.eulerCycleSearcher = eulerCycleSearcher;
		this.dijkstraSearcher = dijkstraSearcher;
	}

	/**
	 * Wyszukuje sciezke listonosza
	 */
	public Path findPostmanPath(final Graph graph) {
		//sprawdz czy graf jest spojny
		if(!isConnectivity(graph)) {
			throw new IllegalArgumentException(Constants.NOT_CONNECTIVITY_GRAPH_EXCEPTION_MSG);
		}
		
		//pobierz liczbe wieszcholkow o nieparzystym stopniu
		int numerOfVertexOddDegree = graph.getAllVertexOddDegree().size();
		Graph graphWithNewEdges = null;
		
		if(numerOfVertexOddDegree != 0) {
			//utworz graf z uzupelnionymi krawedziami
			graphWithNewEdges = dijkstraSearcher.addEdgesToOddVertices(graph);
		} else {
			graphWithNewEdges = graph;
		}
		
		//znajdz sciezke listonosza
		Path postmanPath = findEulerCycle(graphWithNewEdges);
		
		return postmanPath;
	}
	
	/**
	 * Sprawdza czy graf jest spojny
	 * @param graph
	 * @return
	 */
	private boolean isConnectivity(Graph graph) {
		return connectivityChecker.isConnectivity(graph);
	}

	/**
	 * Wyszukuje cykl eurela w grafie
	 * @param graph
	 * @return
	 */
	private Path findEulerCycle(Graph graph) {
		return eulerCycleSearcher.findEulerCycle(graph);
	}

}
